# coding: utf-8
import json
import re
from copy import deepcopy
from string import Template
from typing import Union

import jsonpath
import requests
from pydantic import BaseModel

from common import pytest_config, json_read, json_write
from .data_tools_util import DataToolsUtil
from .random_util import get_faker_data

extract = pytest_config.variables + '/extract.json'


class ExtractUtil:

    @classmethod
    def extract(cls, response: requests.Response, var_name: str, attr: str, expr: str, index: int):
        """
        Extract the value of the specified attribute from the specified expression.
        :param response: Response from the request.
        :param var_name: Name of the variable to extract from the response.
        :param attr: Name of the attribute to extract.
        :param expr: Expression to extract the attribute from.
        :param index: Index of the element to extract.
        :return:
        """
        res = deepcopy(response)
        if attr == 'json':
            res_data = response.json()
        else:
            res_data = getattr(res, attr)
        if expr.startswith('$'):
            lis = jsonpath.jsonpath(dict(res_data), expr)
        else:
            lis = re.findall(expr, res_data)
        data = {}
        if lis:
            data[var_name] = lis[index]
            json_write(data, extract)
        return data

    @classmethod
    def use_extract_value(cls, request_data: Union[BaseModel, dict]) -> dict:
        """
        从指定表达式中提取指定属性的值。
        Extract the value of the specified attribute from the specified expression.
        :param request_data: Request data to extract.
        :return:
        """
        if isinstance(request_data, BaseModel):
            request_data = request_data.dict()
        # 替换提取变量
        temp = Template(json.dumps(request_data, ensure_ascii=False, indent=4))
        new_temp = temp.safe_substitute(json_read(extract))
        # 替换 faker 变量
        faker_vars = re.findall('\\$\\{(.*?)\\}', new_temp)
        for var in faker_vars:
            st = '${' + var + '}'
            if var.startswith('faker.'):
                new_temp = new_temp.replace(st, get_faker_data(var))
            else:
                # 替换自定义函数
                r = re.search("(.*?)\((.*?)\\)", var)
                if r:
                    func = r.group(1)
                    args = r.group(2)

                    if args:
                        value = getattr(DataToolsUtil, func)(*args.split(','))
                    else:
                        value = getattr(DataToolsUtil, func)()

                    new_temp = new_temp.replace(st, value)

        # 序列化 json 格式
        return json.loads(new_temp)
